09 Tipando nossa API

Próxima Atividade
  • Sugerir melhoria
Carregando vídeo

Transcrição

Organizamos o código de maneira mais elegante, e o isolamos em uma camada de serviço. Conseguimos exibir as fotos, mas avançaremos um pouco e adquiriremos maturidade em termos de acesso à API. Quando a acessamos via navegador, recebemos uma lista de objetos com propriedades id, postDate, URL, e outras tantas informações que dizem respeito à cada imagem.

Por ora, só estamos utilizando url e description, certo? Para provar isso, em app.component.ts, criaremos um bloco na arrow function e, no array de photos, queremos acessar o id da imagem da primeira posição. Mas ao digitarmos photos[0]., não são exibidas opções de autocomplete. Se tentarmos incluir url logo em seguida, teremos um erro de compilação.

Quando o código está sendo executado, internamente ele roda como JavaScript, sem tipagem, e por isso funciona. Porém, do ponto de vista do TypeScript, esta lista é do tipo Object[], o qual não possui url ou outras propriedades além de constructor, hasOwnProperty(), isPrototypeOf(), e por aí vai.

Sendo assim, não é possível exibir os dados da primeira imagem, pois utilizamos esta tipagem (Object[]). Vamos tentar trocá-la por any[]:

export class AppComponent {

    photos: any[] = [];

    constructor(photoService: PhotoService) {

        photoService
            .listFromUser('flavio')
            .subscribe(photos => {
                photos[0].
                this.photos = photos
            });
}

Com a tecla "Ctrl" pressionada, e clicando em listFromUser(), acessamos o método, e indicaremos que seu retorno será do tipo any[]:

listFromUser(userName: string) {
    return this.http
        .get<any[]>(API + '/flavio/photos');
}

Voltaremos a app.component.ts, e o autocomplete em photos[0].description continua não funcionando, mas o seu acesso sim. Ou seja, não há mais erro de compilação. E como usamos any[], o tipo poderá ser qualquer um. Incluiremos um console.log() no código, salvaremos, voltaremos ao navegador, abriremos o console, em que encontraremos "Farol iluminado", descrição da primeira imagem.

photoService
    .listFromUser('flavio')
    .subscribe(photos => {
        console.log(photos[0].description);
        this.photos = photos
    });

Resolvemos o nosso problema? Mais ou menos, porque se digitarmos descript em vez de description, o TypeScript não acusará erro, e no console será lido simplesmente "undefined". Além disso, também perdemos o autocomplete ao desenvolvermos a aplicação.

Para corrigirmos isto, tiparemos o retorno da API. Em photo.service.ts informamos que o retorno é do tipo any[], porém trocaremos para Photo[], com propriedades específicas. Então, na pasta "photo", junto ao serviço, criaremos o arquivo photo.ts, que não será um componente, tampouco uma classe, e sim uma interface chamada Photo.

No conceito do TypeScript, a ideia da interface tem a ver com encaixes específicos, e incluiremos nela todas as propriedades dos objetos retornados na lista da API, e atribuiremos um tipo para cada uma delas:

export interface Photo {
    id:number;
    postDate:Date;
    url:string;
    description:string;
    allowComments:boolean;
    likes:number;
    comments:number;
    userId:number;
}

A interface não diz em nenhum momento quais dados precisam estar em cada uma destas propriedades, e sim o shape, a forma que um objeto deve ter.

Em photo.service.ts, importaremos Photo[] clicando no ícone de lâmpada, e o dado será tratado como um array deste tipo. Nisto, app.component.ts começará a dar erro, pois quando acessamos a posição 0 do array, veremos que não existe a propriedade descript.

Com isso, ficamos menos suscetíveis a erros corriqueiros ao acessarmos estas propriedades, pois as padronizamos e tipamos, e somos mais produtivos com o autocomplete. Caso a API mude, a aplicação deixará de funcionar, pois o TypeScript não irá prevenir isso, apenas receberá os dados e tentará tratá-los, sem conseguir acessá-los.

Se o acesso do retorno da API ocorre em inúmeros locais, poderemos abrir a interface, clicar com o botão direito na propriedade alterada, escolher a opção "Rename Symbol", digitar o novo nome e pressionar "Enter". Assim, modificamos o nome da propriedade em todos os locais em que é acessada.

O código de photoService em app.component.ts ficará da seguinte forma:

photoService
    .listFromUser('flavio')
    .subscribe(photos => this.photos = photos);
Tirar dúvida Próxima Atividade
ícone Angular parte 1: Fundamentos

Angular parte 1: Fundamentos

100%
Aula03 de 07

Integração com Web API's

Atividades 9 de 12

  • 01 Projeto da aula anterior
  • 02 SPAs e consumo de APIs 07min
  • 03 (Obrigatório) Baixando e subindo o servidor da API
  • 04 Nomenclatura do servidor
  • 05 HttpClient e injeção de dependência 12min
  • 06 Importando o HttpClient
  • 07 Consumindo dados da API 10min
  • 08 Isolando a acesso em serviços 11min
  • 09 Tipando nossa API 10min
  • 10 Ciclo de vida de um componente 08min
  • 11 Consolidando seu conhecimento
  • 12 O que aprendemos?

Aulas

Outros Links

Fórum Trocar Curso
Gravatar de Marcos Katsumi Kay

Marcos Katsumi Kay 34.0k xp

Logo da Alura